package com.gitee.wsl.compose.ui.navigation

import androidx.compose.runtime.Composable
import androidx.navigation.NavArgumentBuilder
import androidx.navigation.NavBackStackEntry
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty


/**
 * Destination base interface
 *
 * Used to create nav destination instance
 *
 * ```
 * // Example 1
 * val Screen by navDestination<ScreenArgs> {
 *      val args: ScreenArgs = navArgs()
 *      Text(text = "Screen data=${args}")
 * }
 *
 * // Example 2
 * object Screen : NavDestination<ScreenArgs> {
 *     override val name: String = "Screen"
 *
 *     @Composable
 *     override fun NavDestinationScope<ScreenArgs>.Content() {
 *         val args: ScreenArgs = navArgs()
 *         Text(text = "Screen data=${args}")
 *     }
 * }
 *
 * // Example 3
 * val Screen = NavDestination<ScreenArgs>("Screen") {
 *      val args: ScreenArgs = navArgs()
 *      Text(text = "Screen data=${args}")
 * }
 *
 * ```
 */
interface NavDestinationView<Args>  where Args : NavArgumentKey {

    val navDestination: NavDestination<Args>

    @Composable
    fun NavDestinationScope<Args>.Content(backStackEntry: NavBackStackEntry)

}

/**
 * Internal simple NavDestination impl.
 */
internal open class NavDestinationViewImpl<Args: NavArgumentKey>(
    val name: String,
    argumentsMap: Map<Args, NavArgumentBuilder.() -> Unit> = emptyMap(),
    deepLinkUris: List<String> = emptyList(),
    override val navDestination: NavDestination<Args> = object:NavDestination<Args>(){
        override val destinationId: String
            get() = name
        override val argumentsMap = argumentsMap

        override val deepLinkUris = deepLinkUris
    },
    private val content: @Composable NavDestinationScope<Args>.() -> Unit
) : NavDestinationView<Args> {

    @Composable
    override fun NavDestinationScope<Args>.Content(backStackEntry: NavBackStackEntry) {
        content()
    }
}

/**
 * Nav destination delegate impl.
 */
class NavDestinationViewInstanceDelegate<Args:NavArgumentKey> (
    val argumentsMap: Map<Args, NavArgumentBuilder.() -> Unit> = emptyMap(),
    val deepLinkUris: List<String> = emptyList(),
    private val content: @Composable NavDestinationScope<Args>.() -> Unit
) : ReadOnlyProperty<Nothing?, NavDestinationView<Args>> {
    private var destination: NavDestinationView<Args>? = null

    override fun getValue(thisRef: Nothing?, property: KProperty<*>): NavDestinationView<Args> {
        if (destination == null) destination = NavDestinationView(
            property.name,
            argumentsMap,
            deepLinkUris,
            content
        )
        return destination!!
    }
}

/**
 * NavDestination builder.
 *
 * @param name The name of the NavDestination.
 * @param extensions Optional extensions for the NavDestination.
 * @param content Composable function defining the content of the NavDestination.
 * @return A NavDestination instance.
 */
fun <Args:NavArgumentKey> NavDestinationView(
    name: String,
    argumentsMap: Map<Args, NavArgumentBuilder.() -> Unit> = emptyMap(),
    deepLinkUris: List<String> = emptyList(),
    content: @Composable NavDestinationScope<Args>.() -> Unit
): NavDestinationView<Args> = NavDestinationViewImpl(
    name,
    argumentsMap = argumentsMap,
    deepLinkUris = deepLinkUris,
    content = content
)

/**
 * override val argumentsMap: Map<SearchResultNavArgumentKeys, NavArgumentBuilder.() -> Unit> =
 *         mapOf(
 *             SearchResultNavArgumentKeys.SearchNavArgumentKey to {
 *                 type = NavType.StringType
 *             },
 *             SearchResultNavArgumentKeys.CategoryNavArgumentKey to {
 *                 type = NavType.StringType
 *                 nullable = true
 *                 defaultValue = "All"
 *             },
 *         )
 */
fun <Args:NavArgumentKey> navDestinationView(
    argumentsMap: Map<Args, NavArgumentBuilder.() -> Unit> = emptyMap(),
    deepLinkUris: List<String> = emptyList(),
    content: @Composable NavDestinationScope<Args>.() -> Unit
): NavDestinationViewInstanceDelegate<Args> = NavDestinationViewInstanceDelegate(
    argumentsMap = argumentsMap,
    deepLinkUris = deepLinkUris,
    content
)